﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;
using System.Xml;
using JetBrains.ReSharper.TaskRunnerFramework;
using JetBrains.Util;
using log4net;
using Objectware.Silverlight.Testing.Runner.Resharper.Tasks;
using Objectware.Silverlight.Testing.Runner.TestResultService;

namespace Objectware.Silverlight.Testing.Runner.Resharper.Runners
{
	public class SilverlightRunner : RemoteTaskRunner
	{
		private readonly ILog logger = Logging.GetLogger<SilverlightRunner>();
		private readonly TestHarness[] _harnesses;

		private static TestHarness[]	CreateTestHarnesses(RemoteTaskPacket[] packets)
		{
			var harnesses = new Dictionary<string, TestHarness>();
			foreach( var packet in packets )
			{
				foreach( var task in packet.Tasks )
				{
					if( task is MethodTask )
					{
						TestHarness harness;
						string xapPath = ((MethodTask) task).XapPath;
						if( !harnesses.ContainsKey(xapPath))
						{
							harness = new TestHarness(xapPath);
							harnesses[xapPath] = harness;
						} else
						{
							harness = harnesses[xapPath];
						}

						
						harness.MethodsToTest.Add(((MethodTask) task).FullyQualifiedTestMethod);
					}
				}
			}

			return harnesses.Values.ToArray();
		}


		public SilverlightRunner(IRemoteTaskServer server)
			: base(server)
		{
			var projects = new Dictionary<string, string>();

			try
			{
				logger.Info("Constructor");

				var packets = server.GetPackets();

				if (null == packets)
				{
					logger.Info("There are no packets");
					return;
				}
				this._harnesses = CreateTestHarnesses(packets);

				foreach( var harness in this._harnesses )
				{
					ExecutionManager.Instance.Run(harness);	
				}
				
			} catch( Exception ex )
			{
				logger.Fatal(string.Format("Exception : {0}\nStacktrace : {1}", ex.Message, ex.StackTrace));
			}
		}

		public override void ConfigureAppDomain(TaskAppDomainConfiguration configuration)
		{
		}

		private static string GetDetails(RemoteTask task)
		{
			var sb = new StringBuilder();

			sb.AppendLine("  Type : " + task.GetType());

			if( task is ClassTask )
			{
				sb.AppendFormat("    TypeName : {0}", ((ClassTask) task).TypeName);
			}
			if( task is MethodTask )
			{
				sb.AppendFormat("    Method : {0}.{1}", ((MethodTask)task).TestType, ((MethodTask)task).TestMethod);
			}

			return sb.ToString();
		}


		public override TaskResult Execute(TaskExecutionNode node)
		{
			logger.Info(string.Format("Execute : {0}",GetDetails(node.RemoteTask)));

			
			return TaskResult.Success;
		}

		public override TaskResult Finish(TaskExecutionNode node)
		{
			if( node.RemoteTask is MethodTask )
			{
				var methodTask = node.RemoteTask as MethodTask;

				var wait = new ManualResetEvent(false);

				logger.Info(string.Format("Subscribing for result : {0}, {1}", methodTask.TestClassName, methodTask.TestMethod));

				var taskResult = TaskResult.Success;

				ResultsManager.Instance.SubscribeToResult(methodTask.TestClassName,methodTask.TestMethod,
					o=>
						{
							switch( o.Result )
							{
								case TestMethodResult.Error:
									{
										var exception = new SilverlightTaskException(o.Message,o.AdditionalInformation);
										this.Server.TaskException(node.RemoteTask,new [] {new TaskException(exception)});

										taskResult = TaskResult.Error;
									}
									break;
								case TestMethodResult.Inconclusive:
									{
										this.Server.TaskError(node.RemoteTask,o.Message);
										taskResult = TaskResult.Error;
									}
									break;
							}
							wait.Set();
						});

				wait.WaitOne();

				logger.Info(string.Format("Finish : {0}", GetDetails(node.RemoteTask)));

				return taskResult;
			}
			
			return TaskResult.Success;
		}

		public override TaskResult Start(TaskExecutionNode node)
		{
			logger.Info(string.Format("Start : {0}", GetDetails(node.RemoteTask)));
			return TaskResult.Success;
		}
	}
}
